#include <map>
#include <vector>
#include <limits>
#include <queue>
using namespace std;
#include <boost/shared_ptr.hpp>
#include <wx/wx.h>
#include <wx/string.h>
#include <wx/dir.h>
#include <wx/filename.h>
#include <wx/listctrl.h>
#include <wx/volume.h>
#include "wx/dnd.h"
#include "wx/dataobj.h"

#include "RWLock.h"
#include "DirectoryWatcher.h"
#include "ItemInfo.h"
#include "Utils.h"
#include "DirectoryCache.h"
#include "FilePropertiesWatcher.h"
#include "FileOperation.h"
#include "EnhancedStatusBar.h"
#include "MainFrame.h"
#include "MainFrameImpl.h"
#include "SyncQueue.h"
#include "BackgroundIconLoader.h"
#include "Application.h"
#include <Windows.h>
#include <shlobj.h>


WNDPROC oldWndProc;
extern IContextMenu2 *g_pcm2;
extern IContextMenu3 *g_pcm3;


LRESULT CALLBACK WndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
    if (g_pcm3)
    {
        LRESULT lres;
        if (SUCCEEDED(g_pcm3->HandleMenuMsg2(uiMsg, wParam, lParam, &lres)))
        {
            return lres;
        }
    }
    else if (g_pcm2)
    {
        if (SUCCEEDED(g_pcm2->HandleMenuMsg(uiMsg, wParam, lParam)))
        {
            return 0;
        }
    }
    if (uiMsg == WM_DESTROY)
    {
        SetWindowLong((HWND) hwnd, GWL_WNDPROC, (LONG) oldWndProc);
    }
    return CallWindowProc(oldWndProc, hwnd, uiMsg, wParam, lParam);
}

MainFrameImpl::MainFrameImpl( wxWindow* parent )
    :
    MainFrame( parent )
{
    oldWndProc = (WNDPROC) SetWindowLong((HWND) this->GetHWND(), GWL_WNDPROC, (LONG) &WndProc);
    statusBar = new EnhancedStatusBar(this);
    progressBar = new wxGauge(statusBar, wxID_ANY, 100);
    statusBar->SetSize(-1, 23);
    statusBar->SetFieldsCount(3);
    SetStatusBar(statusBar);
    int fieldWidths[] = { -1, 100, 20};
    statusBar->SetStatusWidths(3, fieldWidths);
    wxStaticText *text = new wxStaticText(statusBar, wxID_ANY, "Ready");
    statusBar->AddWidget(text, ESB_ALIGN_LEFT, ESB_ALIGN_CENTER_VERTICAL);
    statusBar->AddWidget(progressBar, ESB_EXACT_FIT_HORIZONTAL, ESB_EXACT_FIT_VERTICAL);
    jobsPanelSizer = new wxBoxSizer(wxVERTICAL);
    jobsPanel->SetSizer( jobsPanelSizer );
    jobsPanelSizer->Fit( jobsPanel );
    compositeFilePanelLeft->GetMainListView()->SetFocus();
    progressBar->Hide();
}
CompositeFilePanel *MainFrameImpl::GetCompisiteFilePanel(unsigned int id)
{
    if (id == 0)
    {
        return compositeFilePanelLeft;
    }
    else if (id == 1)
    {
        return compositeFilePanelRight;
    }
    return NULL;
}
void MainFrameImpl::AddJobWidgets(wxPanel *&panel, wxGauge *&gauge, wxButton *&cancelButton, wxStaticText *&descriptionText)
{
    panel = new wxPanel(jobsPanel, wxID_ANY);
    jobsPanelSizer->Add(panel, 0, wxEXPAND, 0);
    wxBoxSizer *sizer = new wxBoxSizer(wxHORIZONTAL);
    panel->SetSizer(sizer);
    sizer->Fit(panel);
    descriptionText = new wxStaticText(panel, wxID_ANY, "");
    gauge = new wxGauge(panel, wxID_ANY, 100, wxDefaultPosition, wxSize(100, 20));
    cancelButton = new wxButton(panel, wxID_ANY, "Cancel");
    sizer->Add(gauge, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
    sizer->Add(descriptionText, 1, wxALIGN_CENTER_VERTICAL, 0);
    sizer->Add(cancelButton, 0,  wxALIGN_CENTER_VERTICAL, 0);
    sizer->Layout();
    jobsPanel->Layout();
}
void MainFrameImpl::RemovePanel(wxPanel *panel)
{
    jobsPanelSizer->Detach(panel);
    jobsPanelSizer->Layout();
    panel->Hide();
    panel->Destroy();
}
FileOperationProgress MainFrameImpl::CurrentWork(LARGE_INTEGER currentWork)
{
    if (currentWork.QuadPart > numeric_limits<int>::max())
        progressBar->SetValue(currentWork.QuadPart / 1024);
    else
        progressBar->SetValue(currentWork.QuadPart);
    return FOP_PROGRESS_CONTINUE;
}
void MainFrameImpl::TotalWork(LARGE_INTEGER totalWork)
{
    if (totalWork.QuadPart == 0)
        progressBar->Hide();
    else
    {
        if (totalWork.QuadPart > numeric_limits<int>::max())
            progressBar->SetRange(totalWork.QuadPart / 1024);
        else
            progressBar->SetRange(totalWork.QuadPart);
        progressBar->Show();
    }

}


WorkWatcherImpl::WorkWatcherImpl(wxPanel *pPanel, wxGauge *pGauge, wxButton *pCancelButton, wxStaticText *&pDescriptionText) : panel(pPanel), gauge(pGauge), cancelButton(pCancelButton), descriptionText(pDescriptionText), cancelPressed(false)
{

}
WorkWatcherImpl::~WorkWatcherImpl()
{

}
FileOperationProgress WorkWatcherImpl::CurrentWork(LARGE_INTEGER currentWork)
{
    if (totalWork.QuadPart > numeric_limits<int>::max())
        gauge->SetValue(currentWork.QuadPart / 1024);
    else
        gauge->SetValue(currentWork.QuadPart);
    if (currentWork.QuadPart == totalWork.QuadPart)
    {
        ((App*) wxTheApp)->GetMainFrame()->RemovePanel(panel);
    }
    if (cancelPressed)
    {
        ((App*) wxTheApp)->GetMainFrame()->RemovePanel(panel);
        return FOP_PROGRESS_CANCEL;
    }
    return FOP_PROGRESS_CONTINUE;
}
void WorkWatcherImpl::TotalWork(LARGE_INTEGER totalWork)
{
    this->totalWork = totalWork;
    if (totalWork.QuadPart > numeric_limits<int>::max())
        gauge->SetRange(totalWork.QuadPart / 1024);
    else
        gauge->SetRange(totalWork.QuadPart);
}
FileOperationProgress WorkWatcherImpl::CurrentFile(const wxString &file)
{
    descriptionText->SetLabelText(file);
    if (cancelPressed)
    {
        ((App*) wxTheApp)->GetMainFrame()->RemovePanel(panel);
        return FOP_PROGRESS_CANCEL;
    }
    return FOP_PROGRESS_CONTINUE;
}
void WorkWatcherImpl::OnCancelButtonPressed(wxCommandEvent &event)
{
    cancelPressed = true;
}